home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / icmpcmd < prev    next >
Text File  |  1994-03-12  |  11KB  |  503 lines

  1. /* ICMP-related user commands */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <time.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "cmdparse.h"
  9. #include "domain.h"
  10. #include "netuser.h"
  11. #include "internet.h"
  12. #include "timer.h"
  13. #include "ping.h"
  14. #include "misc.h"
  15. #include "Terminal.h"
  16. #include "udp.h"
  17. #include "icmp.h"
  18.  
  19. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  20.  
  21. extern int16 lport;                     /* local port placeholder */
  22.  
  23. static int pingem(int32, int16, int16);
  24. static int16 hash_ping(int32);
  25. static struct ping *add_ping(int32);
  26. static void del_ping(struct ping *);
  27.  
  28. static void send_hop(void);
  29. static int docheck (int argc,char *argv[]);
  30. static int dottl (int argc,char *argv[]);
  31. static int dowait (int argc,char *argv[]);
  32. static int donum (int argc,char *argv[]);
  33.  
  34. struct cmds Hopcmds[] = { 
  35.     "check",    docheck,    2,    "hop check <host>", NULLCHAR,
  36.     "maxttl",    dottl,        0,    0,    NULLCHAR,
  37.     "maxwait",    dowait,      0,    0,    NULLCHAR,
  38.     "queries",    donum,        0,    0,    NULLCHAR,   
  39.     NULLCHAR,   
  40. };
  41.  
  42. /* ICMP message types */
  43. extern char *icmptypes[];
  44.  
  45. /* ICMP unreachable messages */
  46. extern char *unreach[];
  47.  
  48. int dohop(int argc, char *argv[])
  49. {
  50.   return subcmd(Hopcmds, argc, argv);
  51. }
  52.  
  53. int doicmpstat(void)
  54. {
  55.   extern struct icmp_errors icmp_errors;
  56.   extern struct icmp_stats icmp_stats;
  57.   extern char *icmptypes[];
  58.   register int i;
  59.  
  60.   cwprintf(NULL, "ICMP: chksum err %u no space %u icmp %u bdcsts %u\r\n",
  61.   icmp_errors.checksum,icmp_errors.nospace,icmp_errors.noloop,
  62.   icmp_errors.bdcsts);
  63.   cwprintf(NULL, "type  rcvd  sent\r\n");
  64.   for(i=0;i<ICMP_TYPES;i++)
  65.   {
  66.     if(icmp_stats.input[i] == 0 && icmp_stats.output[i] == 0)
  67.       continue;
  68.     cwprintf(NULL, "%-6u%-6u%-6u",i,icmp_stats.input[i],
  69.     icmp_stats.output[i]);
  70.     if(icmptypes[i] != NULLCHAR)
  71.       cwprintf(NULL, "  %s",icmptypes[i]);
  72.     cwprintf(NULL, "\r\n");
  73.   }
  74.   return 0;
  75. }
  76.  
  77. /* Hash table list heads */
  78. struct ping *ping[PMOD];
  79.  
  80. /* Counter for generating seq numbers */
  81. static int16 iclk;
  82.  
  83. /* Increment counter -- called by low level clock tick */
  84. void icmpclk(void)
  85. {
  86.   iclk++;
  87. }
  88.  
  89. static int32 cticks;
  90. static int16 hopttl;
  91. static int16 hopquery;
  92. static struct socket lsocket, fsocket;    /* socket address */
  93. static int32 lastsource;
  94. static int32 hopmean;
  95. static struct timer hop_time_t;
  96. static Terminal *window;
  97.  
  98. static int16 Hopmaxttl   = 30;        /* max attempts */
  99. static int16 Hopmaxwait  = 5;        /* secs timeout each attempt */
  100. static int16 Hopmaxquery = 3;        /* #probes each attempt */
  101.  
  102. /* Set/show # queries sent each TTL value */
  103. static int donum(int argc, char *argv[])
  104. {
  105.   int n = atoi(argv[1]);
  106.   
  107.   if (argc < 2)
  108.   {
  109.     cwprintf(NULL, "%d checks for each host\n", Hopmaxquery);
  110.   }
  111.   else if (n < 1 || n > HOPMAXQUERY)
  112.   {
  113.     cwprintf(NULL, "Checks for each host must be > 0 and <= %d\n", HOPMAXQUERY);
  114.     return (1);
  115.   }
  116.   else
  117.   {
  118.     Hopmaxquery = n;
  119.   }
  120.   return (0);
  121. }
  122.  
  123. /* Set/show maximum TTL value for a traceroute query */
  124. static int dottl(int argc, char *argv[])
  125. {
  126.   int n = atoi(argv[1]);
  127.   
  128.   if (argc < 2)
  129.   {
  130.     cwprintf(NULL, "Maximum ttl %d\n", Hopmaxttl);
  131.   }
  132.   else if (n < 2 || n > 255)
  133.   {
  134.     cwprintf(NULL, "Maximum ttl must be > 0 and <= 255\n");
  135.     return (1);
  136.   }
  137.   else
  138.   {
  139.     Hopmaxttl = n;
  140.   }
  141.   return (0);
  142. }
  143.  
  144. static void hop_timeout(void *vp)
  145. {
  146.   if (hopquery == 1)
  147.   {
  148.     if (lastsource != 0)
  149.     {
  150.       cwprintf(window, " (mean %ld)", 10 * hopmean / Hopmaxquery);
  151.       hopmean = 0;
  152.     }
  153.     cwprintf(window, "\n%3d %-18s", hopttl, inet_ntoa(0));
  154.   }
  155.   cticks = clock() - cticks;
  156.   cwprintf(window, "  ***  ");
  157.   hopmean += cticks;
  158.   send_hop();
  159. }
  160.  
  161. /* Set/show #secs until timeout for a traceroute query */
  162. static int dowait(int argc, char *argv[])
  163. {
  164.   int n = atoi(argv[1]);
  165.   
  166.   if (argc < 2)
  167.   {
  168.     cwprintf(NULL, "Maximum wait for reply %d\n", Hopmaxwait);
  169.   }
  170.   else if (n < 1)
  171.   {
  172.     cwprintf(NULL, "Maximum wait for reply must be > 0\n");
  173.     return (1);
  174.   }
  175.   else
  176.   {
  177.     Hopmaxwait = n;
  178.   }
  179.   return (0);
  180. }
  181.  
  182. static void send_hop(void)
  183. {
  184.   if (hopquery >= Hopmaxquery)
  185.   {
  186.     hopquery = 0;
  187.     hopttl++;
  188.   }
  189.   if (hopttl < Hopmaxttl)
  190.   {
  191.     send_udp(&lsocket, &fsocket, 0, hopttl, 0, 0, 0, 0);
  192.     cticks = clock();
  193.     hopquery++;
  194.     hop_time_t.func = hop_timeout;  /* what to call on timeout */
  195.     hop_time_t.arg  = NULL;
  196.     set_timer(&hop_time_t, Hopmaxwait * 1000L);
  197.     start_timer(&hop_time_t);
  198.   }
  199. }
  200.  
  201. void hop_rec(struct icmp *icmphdr, struct udp *udphdr, int32 source, int16 type)
  202. {
  203.   BOOL tracedone = FALSE;
  204.   struct socket fsocket;    /* socket address    */
  205.  
  206.   if (udphdr->source != lsocket.port)
  207.     return;
  208.  
  209.   stop_timer(&hop_time_t);
  210.   if (lastsource != source)
  211.   {
  212.     if (lastsource != 0)
  213.     {
  214.       cwprintf(window, " (mean %ldms)", 10 * hopmean / Hopmaxquery);
  215.       hopmean = 0;
  216.     }
  217.     cwprintf(window, "\n%3d %-15s", hopttl, inet_ntoa(source));
  218.   }
  219.   lastsource = source;
  220.   cticks = clock() - cticks;
  221.   cwprintf(window, " %4ldms", 10 * cticks);
  222.   hopmean += cticks;
  223.  
  224.   if (icmphdr->type == DEST_UNREACH)
  225.   {
  226.     switch(icmphdr->code)
  227.     {
  228.     case PORT_UNREACH:
  229.       ++tracedone;
  230.       break;
  231.     case NET_UNREACH:
  232.       ++tracedone;
  233.       cwprintf(window, " !N");
  234.       break;
  235.     case HOST_UNREACH:
  236.       ++tracedone;
  237.       cwprintf(window, " !H");
  238.       break;
  239.     case PROT_UNREACH:
  240.       ++tracedone;
  241.       cwprintf(window, " !P");
  242.       break;
  243.     case FRAG_NEEDED:
  244.       ++tracedone;
  245.       cwprintf(window, " !F");
  246.       break;
  247.     case ROUTE_FAIL:
  248.       ++tracedone;
  249.       cwprintf(window, " !S");
  250.       break;
  251.     case ADMIN_PROHIB:
  252.       ++tracedone;
  253.       cwprintf(window, " !A");
  254.       break;
  255.     default:
  256.       cwprintf(window, " !?");
  257.       break;
  258.     }
  259.   }
  260.   if (!tracedone)
  261.     send_hop();
  262.  
  263.   if (tracedone || hopttl >= Hopmaxttl)
  264.   {
  265.     cwprintf(window, "\n\ntraceroute done: ");
  266.     if (hopttl >= Hopmaxttl)
  267.     {
  268.       cwprintf(window, "!! maximum TTL exceeded\n");
  269.     } 
  270.     else if (source == fsocket.address && icmphdr->code == DEST_UNREACH)
  271.     {
  272.       cwprintf(window, "normal (%s %s)\n", icmptypes[type], unreach[icmphdr->code]);
  273.     }
  274.     else
  275.     {
  276.       cwprintf(window, "!! %s %s\n", icmptypes[type], unreach[icmphdr->code]);
  277.     }
  278.     window->Attr = ATTR_REVERSE;
  279.     window->Flags.flags.dont_destroy = FALSE;
  280.     cwprintf(window, "\nThis session has finished, please close the window\n");
  281.     window = NULL;
  282.   }
  283. }
  284.  
  285. static int docheck(int argc, char *argv[])
  286. {
  287.   char title[80];
  288.   
  289.   /* Set up the connection. */
  290.   fsocket.address = resolve(argv[1]);
  291.   if (fsocket.address != 0)
  292.   {
  293.     fsocket.port    = (int16) (32768L+666);
  294.     lsocket.address = ip_addr;      /* our ip address */
  295.     lsocket.port    = lport++;      /* next unused port */
  296.   
  297.     hopttl     = 0;
  298.     hopquery   = Hopmaxquery;
  299.     lastsource = 0;
  300.     hopmean    = 0;
  301.     
  302.     sprintf(title, "Hop check to %s", argv[1]);
  303.     window = Window_Open(NULL, title, term_NO_INPUT); 
  304.     send_hop();
  305.   }
  306.   else
  307.   {
  308.     cwprintf(NULL, "Hop - Can't resolve %s\n", argv[1]);
  309.   }
  310.   return(0);
  311. }
  312.  
  313. /* Send ICMP Echo Request packets */
  314. int doping(int argc, char **argv)
  315. {
  316.   int32 dest;
  317.   struct ping *pp1;
  318.   register struct ping *pp;
  319.   int16 hval;
  320.   int i;
  321.  
  322.   if(argc < 2)
  323.   {
  324.     cwprintf(NULL, "Host                Sent    Rcvd   %%   Avg RTT  Interval\r\n");
  325.     for (i = 0; i < PMOD; i++)
  326.     {
  327.       for (pp = ping[i]; pp != NULLPING; pp = pp->next)
  328.       {
  329.         cwprintf(NULL, "%-16s",inet_ntoa(pp->remote));
  330.         cwprintf(NULL, "%8lu%8lu", pp->count, pp->echoes);
  331.         cwprintf(NULL, "%4lu%10lu%10lu\r\n",
  332.         (long)pp->echoes * 100 / pp->count,
  333.         pp->echoes != 0 ? 
  334.         (long)pp->ttotal * MSPTICK / pp->echoes : 0,
  335.         ((long)pp->timer.start * MSPTICK + 500) / 1000);
  336.       }
  337.     }
  338.     return 0;
  339.   }
  340.   if (strcmp(argv[1],"clear") == 0)
  341.   {
  342.     for(i = 0; i < PMOD; i++)
  343.     {
  344.       for (pp = ping[i]; pp != NULLPING; pp = pp1)
  345.       {
  346.         pp1 = pp->next;
  347.         del_ping(pp);
  348.       }
  349.     }
  350.     return 0;
  351.   }
  352.   if ((dest = resolve(argv[1])) == 0)
  353.   {
  354.     cwprintf(NULL, "Host %s unknown\r\n",argv[1]);
  355.     return 1;
  356.   }
  357.   /* See if dest is already in table */
  358.   hval = hash_ping(dest);
  359.   for (pp = ping[hval]; pp != NULLPING; pp = pp->next)
  360.   {
  361.     if(pp->remote == dest)
  362.     {
  363.       break;
  364.     }
  365.   }
  366.   if(argc > 2)
  367.   {
  368.     /* Inter-ping time is specified; set up timer structure */
  369.     if(pp == NULLPING)
  370.       pp = add_ping(dest);
  371.     if (pp->window != NULL)
  372.       cwtitle(pp->window, "Ping - %s", argv[1]);
  373.     pp->timer.start = atoi(argv[2]) * (int32)(1000 / MSPTICK);
  374.     pp->timer.func = ptimeout;
  375.     pp->timer.arg = (char *)pp;
  376.     pp->remote = dest;
  377.     start_timer(&pp->timer);
  378.     pp->count++;
  379.     pingem(dest, iclk, REPEAT);
  380.   } 
  381.   else
  382.     pingem(dest, iclk, ONESHOT);
  383.  
  384.   return 0;
  385. }
  386.  
  387. /* Called by ping timeout */
  388. void ptimeout(char *p)
  389. {
  390.   register struct ping *pp;
  391.  
  392.   /* Send another ping */
  393.   pp = (struct ping *)p;
  394.   pp->count++;
  395.   pingem(pp->remote,iclk,REPEAT);
  396.   start_timer(&pp->timer);
  397. }
  398. /* Send ICMP Echo Request packet */
  399. static int pingem(int32 dest, int16 seq, int16 id)
  400. {
  401.   struct mbuf *bp;
  402.   struct icmp icmp;
  403.   extern struct icmp_stats icmp_stats;
  404.  
  405.   icmp_stats.output[ECHO]++;
  406.   icmp.type = ECHO;
  407.   icmp.code = 0;
  408.   icmp.args.echo.seq = seq;
  409.   icmp.args.echo.id = id;
  410.   if((bp = htonicmp(&icmp,NULLBUF)) == NULLBUF)
  411.     return 0;
  412.   return ip_send(ip_addr,dest,ICMP_PTCL,0,0,bp,len_mbuf(bp),0,0);
  413. }
  414.  
  415. /* Called with incoming Echo Reply packet */
  416. void echo_proc(int32 source, int32 dest, struct icmp *icmp)
  417. {
  418.   register struct ping *pp;
  419.   int16 hval;
  420.   int16 rtt;
  421.  
  422.   dest = dest;
  423.  
  424.   rtt = iclk - icmp->args.echo.seq;
  425.   hval = hash_ping(source);
  426.   for(pp = ping[hval]; pp != NULLPING; pp = pp->next)
  427.     if(pp->remote == source)
  428.       break;
  429.   if (pp == NULLPING || icmp->args.echo.id != 1)
  430.   {
  431.     cwprintf(NULL, "%s: echo reply id %u seq %u, %lu ms\r\n",
  432.     inet_ntoa(source),
  433.     icmp->args.echo.id,icmp->args.echo.seq,
  434.     (long)rtt * MSPTICK);
  435.   } 
  436.   else if (pp->window != NULL)
  437.   {
  438.     cwprintf(pp->window, "echo reply id %u seq %u, %lu ms\r\n",
  439.     icmp->args.echo.id,icmp->args.echo.seq,
  440.     (long)rtt * MSPTICK);
  441.   }
  442.   else
  443.   {
  444.     /* Repeated poll, just keep stats */
  445.     pp->ttotal += rtt;
  446.     pp->echoes++;
  447.   }
  448. }
  449.  
  450. static int16 hash_ping(int32 dest)
  451. {
  452.   int16 hval;
  453.  
  454.   hval = (hiword(dest) ^ loword(dest)) % PMOD;
  455.   return hval;
  456. }
  457. /* Add entry to ping table */
  458. static struct ping * add_ping(int32 dest)
  459. {
  460.   struct ping *pp;
  461.   int16 hval;
  462.  
  463.   pp = (struct ping *)calloc(1,sizeof(struct ping));
  464.   if(pp == NULLPING)
  465.     return NULLPING;
  466.  
  467.   hval = hash_ping(dest);
  468.   pp->prev = NULLPING;
  469.   pp->next = ping[hval];
  470.   if(pp->next != NULLPING)
  471.     pp->next->prev = pp;
  472.   ping[hval] = pp;
  473.   pp->window = Window_Open(NULL, "Ping", term_NO_INPUT); 
  474.   return pp;
  475. }
  476. /* Delete entry from ping table */
  477. static void del_ping(struct ping *pp)
  478. {
  479.   int16 hval;
  480.  
  481.   stop_timer(&pp->timer);
  482.  
  483.   if(pp->next != NULLPING)
  484.     pp->next->prev = pp->prev;
  485.   if(pp->prev != NULLPING)
  486.   {
  487.     pp->prev->next = pp->next;
  488.   }
  489.   else
  490.   {
  491.     hval = hash_ping(pp->remote);
  492.     ping[hval] = pp->next;
  493.   }
  494.   if (pp->window)
  495.   {
  496.     pp->window->Attr = ATTR_REVERSE;
  497.     pp->window->Flags.flags.dont_destroy = FALSE;
  498.     cwprintf(pp->window, "\nThis session has finished, please close the window\n");
  499.   }
  500.   free((char *)pp);       
  501. }
  502.  
  503.